import datetime
import json
import os
import sys
import threading
import time
from contextlib import contextmanager

from flask import Flask, request, jsonify, session, render_template
from flask_cors import CORS
from flask_socketio import SocketIO, emit, join_room

from main import get_cookie, get_all, submit, userid


def save_to_json(username, message):
    data = {}
    if os.path.exists("history.json"):
        with open("history.json", "r", encoding="utf-8") as file:
            data = json.load(file)
    if username not in data:
        data[username] = []
    data[username].append(message)

    with open("history.json", "w", encoding="utf-8") as file:
        json.dump(data, file, ensure_ascii=False, indent=4)


app = Flask(__name__)
app.config["SECRET_KEY"] = "secret!"
CORS(app)
socketio = SocketIO(app, cors_allowed_origins="*")


class WebSocketOutput:
    def __init__(self, socketio, room):
        self.socketio = socketio
        self.room = room

    def write(self, s):
        current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        save_to_json(self.room, f"{current_time} {s}")
        self.socketio.emit(
            "data_updated", {"message": f"{current_time} {s}"}, room=self.room
        )

    def flush(self):
        pass


@contextmanager
def redirect_stdout_to_socket(socketio, room):
    original_stdout = sys.stdout
    sys.stdout = WebSocketOutput(socketio, room)
    yield
    sys.stdout = original_stdout


threads = {}
stop_signals = {}
online_users = set()


def clean(username):
    threads.pop(username, None)
    stop_signals.pop(username, None)


def background_task(username, password, course):
    with redirect_stdout_to_socket(socketio, room=username):
        print(f"开始选课，选课课程为：{' '.join(course)}")
        print("=================================")
        print("开始登陆...")
        try:
            cookie = get_cookie(username, password)
        except Exception as e:
            print(f"登录失败，可能是账号密码错误, Error: {e}")
            clean(username)
            return
        count = 0
        while True:
            if stop_signals.get(username, False):
                stop_signals[username] = False
                socketio.server.emit(
                    "data_updated", {"message": "Task Stopped"}, room=username
                )
                clean(username)
                return
            data = get_all(cookie, course)
            count += 1
            if data == -1:
                if count == 5:
                    print("===多次失败，请重试或联系管理员...")
                    clean(username)
                    return
                print(f"===第{count}次，未成功获取到数据，可能是cookie过期，正在重新获取cookie...")
                cookie = ""  # get_cookie(username, password)
                time.sleep(1)
                continue
            count = 0
            print(userid, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            for i in data:
                print(f"{i[2]}, {i[6]}, {i[3]}")
                if int(i[3]) > 0 and i[0].isdigit():
                    print("正在抢课........................")
                    t = submit(cookie, i[0])
                    print("抢课成功", t)
            print(
                "--------------------------------------------------------------------"
            )
    clean(username)
    socketio.server.emit("data_updated", {"message": "Task Completed"}, room=username)


@app.route("/room_status/<string:room_name>", methods=["GET"])
def room_status(room_name):
    clients = socketio.server.rooms(room_name)
    if clients:
        return jsonify({"status": "active", "clients": len(clients)})
    else:
        return jsonify({"status": "empty"})


@app.route("/submit", methods=["POST"])
def submit_form():
    data = request.json
    username = data["username"]
    if username in threads:
        socketio.server.emit(
            "data_updated",
            {"message": "Task already running for this user."},
            room=username,
        )
        return jsonify({"message": "Task already running for this user."}), 400
    stop_signals[username] = False
    thread = threading.Thread(
        target=background_task, args=(username, data["password"], data["course"])
    )
    threads[username] = thread
    socketio.server.emit("data_updated", {"message": "Task started"}, room=username)
    thread.start()
    return jsonify({"message": "Task started."})


@app.route("/stop", methods=["POST"])
def stop_run():
    data = request.json
    username = data["username"]
    if username == "" or username not in threads:
        return jsonify({"message": "No task running for this user."}), 400
    if username in threads:
        with redirect_stdout_to_socket(socketio, room=username):
            print("正在停止...")
            print("=================================")
            stop_signals[username] = True
    return jsonify({"message": "Task stop signal sent."})


@socketio.on("join")
def on_join(data):
    username = data["username"]
    session["username"] = username
    online_users.add(username)
    join_room(username)
    emit(
        "data_updated", {"message": username + " has entered the room."}, room=username
    )


@socketio.on("disconnect")
def handle_disconnect():
    print('A user disconnected')
    username = session.get("username")
    if username:
        online_users.remove(username)
        threads.pop(username, None)
        stop_signals.pop(username, None)


def is_admin(token):
    ADMIN_TOKEN = "heziah-xuanke-backend"
    return token == ADMIN_TOKEN


@app.route("/admin")
def admin_dashboard():
    print(online_users)
    token = request.args.get("token")
    if not is_admin(token):
        return "Unauthorized", 403
    # 获取线程和对话数据
    return render_template("admin.html", threads=threads, online_users=online_users)


@app.route("/admin/stop_thread", methods=["POST"])
def stop_thread():
    # token = request.args.get('token')
    # if not is_admin(token):
    #     return "Unauthorized", 403
    username = request.json["username"]  # 获取JSON数据而不是表单数据
    if username in threads and username in stop_signals:
        stop_signals[username] = True
    return jsonify({"message": f"Thread for {username} has been signalled to stop."})


@app.route("/admin/user_history/<string:username>", methods=["GET"])
def display_user_history(username):
    # token = request.args.get('token')
    # if not is_admin(token):
    #     return "Unauthorized", 403

    if os.path.exists("history.json"):
        with open("history.json", "r", encoding="utf-8") as file:
            data = json.load(file)
            user_history = data.get(username, [])
        return render_template(
            "user_history.html", username=username, messages=user_history
        )
    else:
        return f"No history found for {username}"


@app.route("/admin/all_users", methods=["GET"])
def get_all_users():
    # token = request.args.get('token')
    # if not is_admin(token):
    #     return "Unauthorized", 403

    if os.path.exists("history.json"):
        with open("history.json", "r", encoding="utf-8") as file:
            data = json.load(file)
            users = list(data.keys())
        return jsonify(users)
    else:
        return jsonify([])


if __name__ == "__main__":
    socketio.run(app, host='0.0.0.0', port=5000)
